package tianrun.ziguan.api.calculate.config.service.sync.impl;

import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tianrun.ziguan.api.calculate.config.constant.StringPools;
import tianrun.ziguan.api.calculate.config.dto.request.common.list.FilterField;
import tianrun.ziguan.api.calculate.config.dto.request.common.list.ListBody;
import tianrun.ziguan.api.calculate.config.dto.request.sync.SyncBody;
import tianrun.ziguan.api.calculate.config.dto.request.sync.SyncData;
import tianrun.ziguan.api.calculate.config.entity.TCalAsset;
import tianrun.ziguan.api.calculate.config.entity.TGeModule;
import tianrun.ziguan.api.calculate.config.enums.MoldEnum;
import tianrun.ziguan.api.calculate.config.enums.SourceTypeEnum;
import tianrun.ziguan.api.calculate.config.listener.RefreshCacheListener;
import tianrun.ziguan.api.calculate.config.service.cal.asset.ITCalAssetService;
import tianrun.ziguan.api.calculate.config.service.common.CommonService;
import tianrun.ziguan.api.calculate.config.service.ge.TGeModuleService;
import tianrun.ziguan.api.calculate.config.service.sync.SyncService;
import tianrun.ziguan.api.calculate.config.service.sync.SyncType;
import tianrun.ziguan.api.calculate.config.service.sync.handler.SyncHandler;
import tianrun.ziguan.api.calculate.config.utils.CollectionUtil;
import tianrun.ziguan.api.calculate.config.utils.MapUtil;
import tianrun.ziguan.api.common.util.ListUtil;
import tianrun.ziguan.api.common.util.SpringContextUtil;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class SyncServiceImpl implements SyncService {

    private final Map<SyncType, Map<MoldEnum, SyncHandler>> doSyncMap;
    private final TGeModuleService geModuleService;
    public SyncServiceImpl(List<SyncHandler> list, TGeModuleService geModuleService) {
        this.doSyncMap = list.stream().collect(Collectors.groupingBy(SyncHandler::type, Collectors.toMap(SyncHandler::mold, Function.identity())));
        this.geModuleService = geModuleService;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void doSync(SyncBody body) {
        body.getSource().forEach((mold, ids) -> {
            SyncData syncData = new SyncData(body.getType(), mold, ids, body.getRange());
            this.doSync(syncData);
        });
    }

    @Override
    public void doSync(SyncData syncData) {
        Set<Long> moduleIds = syncData.getModuleIds();
        if (CollectionUtil.isEmpty(moduleIds)) {
            return;
        }
        SyncHandler handler = doSyncMap.get(syncData.getType()).get(syncData.getSourceMold());
        if (handler == null) {
            return;
        }
        handler.handler(moduleIds, syncData.getTemplateIds());
        //刷缓存
        if (Objects.equals(syncData.getType(), SyncType.ASSET)) {
            syncData.getTemplateIds().forEach(RefreshCacheListener::flushByAssetId);
        }

    }

    @Override
    public void doSync(List<TCalAsset> assetList) {
        if (CollectionUtil.isEmpty(assetList)) return;
        List<TCalAsset> collect = assetList.stream().filter(asset -> Objects.nonNull(asset.getId())).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(collect)) return;

        CommonService commonService = SpringContextUtil.getBean(CommonService.class);
        Map<Long, List<TCalAsset>> listMap = ListUtil.groupList(collect, TCalAsset::getTemplateId);

        List<TGeModule> geModules = geModuleService.listByCType(SourceTypeEnum.TEMPLATE);

        listMap.forEach((templateId, tCalAssets) -> {
            //虚拟模板跳过
            if (Objects.equals(templateId,0L))return;
            HashMap<MoldEnum, Set<Long>> sourceMap = new HashMap<>();
            ArrayList<FilterField> filterFields = Lists.newArrayList(FilterField.equal(StringPools.VALID, 1), FilterField.equal(StringPools.TEMPLATE_ID, templateId));
            geModules.forEach(tGeModule -> {
                String tableName = tGeModule.getTableName();
                MoldEnum mold = MoldEnum.valueOf(tGeModule.getMold());
                List<Map<String, Object>> list = commonService.list(ListBody.of(filterFields,Lists.newArrayList("id"), tableName));
                sourceMap.put(mold,list.stream().map(bean -> MapUtil.getLong(bean,"id")).collect(Collectors.toSet()));
            });

            SyncBody syncBody = new SyncBody();
            syncBody.setSource(sourceMap);
            syncBody.setType(SyncType.ASSET);
            syncBody.setRange(tCalAssets.stream().map(TCalAsset::getId).collect(Collectors.toSet()));
            doSync(syncBody);
        });
    }
}
